/** ============================================================================
 *  @file   MatrixARM.c
 *
 *  @path   
 *
 *  @desc   This is an application which create 2 matrixes and computed the product of 2 matrixes 
 *          send to the DSP. The product of 2 matrixes is sent back from DSP and compared
 *          with local answer to ensure the correctness.
 *          Experiment, Silent, Verify Mode can be enable individually during compilation time.
 *          (Enable by define it, check *Mode selection*)
 *
*/
/*  ----------------------------------- DSP/BIOS Link                   */
#include <dsplink.h>

/*  ----------------------------------- DSP/BIOS LINK API               */
#include <proc.h>
#include <msgq.h>
#include <pool.h>

/*  ----------------------------------- Application Header              */
#include <MatrixARM.h>
#include <system_os.h>

#include <stdio.h>
#include <string.h>


#if defined (__cplusplus)
extern "C" {
#endif /* defined (__cplusplus) */

//***************************Mode selection*********************************
/*#if !defined (EXPERIMENT)
#define EXPERIMENT
#define PROFILE
#define SILENT
#endif*/

/*#if !defined(SILENT)
#define SILENT
#endif
*/
    
#if !defined (PROFILE)
#define PROFILE
#endif

#if !defined (VERIFY_DATA)
#define VERIFY_DATA
#endif
//**************************************************************************


/* Number of arguments specified to the DSP application. */
#define NUM_ARGS 1

/* Argument size passed to the control message queue */
#define ARG_SIZE        30
#define INT_ARG_SIZE    (128*127)+81

/* ID of the POOL used by MatrixARM. */
#define SAMPLE_POOL_ID  0

/*  Number of BUF pools in the entire memory pool */
#define NUMMSGPOOLS     4

/* Number of messages in each BUF pool. */
#define NUMMSGINPOOL0   1
#define NUMMSGINPOOL1   2
#define NUMMSGINPOOL2   2
#define NUMMSGINPOOL3   4

/* Control message data structure. */
/* Must contain a reserved space for the header */
typedef struct ControlMsg 
{
    MSGQ_MsgHeader header;
    Uint16 command;
    Uint16 PackageEntries;
    Uint32 int_arg[INT_ARG_SIZE];
    Char8 arg1[ARG_SIZE];
} ControlMsg;

ControlMsg Gmsg;

/* Messaging buffer used by the application.
 * Note: This buffer must be aligned according to the alignment expected
 * by the device/platform. */
#define APP_BUFFER_SIZE DSPLINK_ALIGN (sizeof (ControlMsg), DSPLINK_BUF_ALIGN)

/* Definitions required for the sample Message queue.
 * Using a Zero-copy based transport on the shared memory physical link. */
#if defined ZCPY_LINK
#define SAMPLEMQT_CTRLMSG_SIZE  ZCPYMQT_CTRLMSG_SIZE
STATIC ZCPYMQT_Attrs mqtAttrs;
#endif


#define SIZE_MAX_MATRIX         128
#define SIZE_PACKAGE_ENTRIES    10
#define SIZE_CHARLIST           SIZE_MAX_MATRIX*SIZE_MAX_MATRIX*4+1
#define INVALID_MATRIX_PTR      SIZE_MAX_MATRIX+1
#define COMMAND_CONTINUE        0x55
#define COMMAND_TERMINATE       0xAA


#if !defined (MATRIX_INFO_H)
#define MATRIX_INFO_H
#define MAX_MATRIX 128
STATIC Uint32  mat1[MAX_MATRIX][MAX_MATRIX], mat2[MAX_MATRIX][MAX_MATRIX], prod_arm[MAX_MATRIX][MAX_MATRIX], prod_dsp[MAX_MATRIX][MAX_MATRIX];
#endif

/* Message sizes managed by the pool */
STATIC Uint32 SampleBufSizes[NUMMSGPOOLS] =
{
    APP_BUFFER_SIZE,
    SAMPLEMQT_CTRLMSG_SIZE,
    DSPLINK_ALIGN (sizeof(MSGQ_AsyncLocateMsg), DSPLINK_BUF_ALIGN),
    DSPLINK_ALIGN (sizeof(MSGQ_AsyncErrorMsg), DSPLINK_BUF_ALIGN)
};

/* Number of messages in each pool */
STATIC Uint32 SampleNumBuffers[NUMMSGPOOLS] =
{
    NUMMSGINPOOL0,
    NUMMSGINPOOL1,
    NUMMSGINPOOL2,
    NUMMSGINPOOL3
};

/* Definition of attributes for the pool based on physical link used by the transport */
#if defined ZCPY_LINK
STATIC SMAPOOL_Attrs SamplePoolAttrs =
{
    NUMMSGPOOLS,
    SampleBufSizes,
    SampleNumBuffers,
    TRUE   /* If allocating a buffer smaller than the POOL size, set this to FALSE */
};
#endif

/* Name of the first MSGQ on the GPP and on the DSP. */
STATIC Char8 SampleGppMsgqName[DSP_MAX_STRLEN] = "GPPMSGQ1";
STATIC Char8 SampleDspMsgqName[DSP_MAX_STRLEN] = "DSPMSGQ";

/* Local GPP's and DSP's MSGQ Objects. */
STATIC MSGQ_Queue SampleGppMsgq = (Uint32) MSGQ_INVALIDMSGQ;
STATIC MSGQ_Queue SampleDspMsgq = (Uint32) MSGQ_INVALIDMSGQ;

/* Place holder for the MSGQ name created on DSP */
Char8 dspMsgqName[DSP_MAX_STRLEN];

/* Extern declaration to the default DSP/BIOS LINK configuration structure. */
extern LINKCFG_Object LINKCFG_config;

/** ============================================================================
 *  @func   Create_Matrix
 *
 *  @desc   This function assign value to Matrixs, mat1 and mat2.
 *  ============================================================================
 */
NORMAL_API Void Create_Matrix(IN Uint8 MatrixSize){
    Uint32 i=0, j=0;
    SYSTEM_2Print ("========== create a matrix of (%d x %d)  ==========\n", MatrixSize,MatrixSize);

    for (i = 0;i < MatrixSize; i++)
    {
        for (j = 0; j < MatrixSize; j++)
        {
            mat1[i][j] = i+j*2;
        }
    }
    for (i = 0;i < MatrixSize; i++)
    {
        for (j = 0; j < MatrixSize; j++)
        {
            mat2[i][j] = i+j*3;
        }
    }
}

#if defined (VERIFY_DATA)
/** ============================================================================
 *  @func   Verify
 *
 *  @desc   This function compare the 2 different Matrixes and 
 *          print out mismatch location.
 *
 *  @modif  None
 *  ============================================================================
 */
void Verify(Uint32 mat1[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 mat2[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 size);
#endif


/** ============================================================================
 *  @func   MatrixARM_Create
 *
 *  @desc   This function allocates and initializes resources used by
 *          this application.
 *
 *  @modif  MatrixARM_InpBufs , MatrixARM_OutBufs
 *  ============================================================================
 */
NORMAL_API DSP_STATUS MatrixARM_Create(IN Char8* dspExecutable, IN Char8* strMatrixSize, IN Uint8 processorId)
{
    DSP_STATUS status = DSP_SOK;
    Uint32 numArgs = NUM_ARGS;
    //Uint8 MatrixSize = SYSTEM_Atoi(strMatrixSize);
    MSGQ_LocateAttrs syncLocateAttrs;
    Char8* args[NUM_ARGS];

    SYSTEM_0Print("Entered MatrixARM_Create ()\n");

    /* Create and initialize the proc object. */
    status = PROC_setup(NULL);

    /* Attach the Dsp with which the transfers have to be done. */
    if (DSP_SUCCEEDED(status))
    {
        status = PROC_attach(processorId, NULL);
        if (DSP_FAILED(status))
        {
            SYSTEM_1Print("PROC_attach () failed. Status = [0x%x]\n", status);
        }
    }

    /* Open the pool. */
    if (DSP_SUCCEEDED(status))
    {
        status = POOL_open(POOL_makePoolId(processorId, SAMPLE_POOL_ID), &SamplePoolAttrs);
        if (DSP_FAILED(status))
        {
            SYSTEM_1Print("POOL_open () failed. Status = [0x%x]\n", status);
        }
    }
    else
    {
        SYSTEM_1Print("PROC_setup () failed. Status = [0x%x]\n", status);
    }

    /* Open the GPP's message queue */
    if (DSP_SUCCEEDED(status))
    {
        status = MSGQ_open(SampleGppMsgqName, &SampleGppMsgq, NULL);
        if (DSP_FAILED(status))
        {
            SYSTEM_1Print("MSGQ_open () failed. Status = [0x%x]\n", status);
        }
    }

    /* Set the message queue that will receive any async. errors */
    if (DSP_SUCCEEDED(status))
    {
        status = MSGQ_setErrorHandler(SampleGppMsgq, POOL_makePoolId(processorId, SAMPLE_POOL_ID));
        if (DSP_FAILED(status))
        {
            SYSTEM_1Print("MSGQ_setErrorHandler () failed. Status = [0x%x]\n", status);
        }
    }

    /* Load the executable on the DSP. */
    if (DSP_SUCCEEDED(status))
    {
        args [0] = strMatrixSize;
        {
            status = PROC_load(processorId, dspExecutable, numArgs, args);
        }
        if (DSP_FAILED(status))
        {
            SYSTEM_1Print("PROC_load () failed. Status = [0x%x]\n", status);
        }
    }

     /* Start execution on DSP. */
    if (DSP_SUCCEEDED(status))
    {
        status = PROC_start(processorId);
        if (DSP_FAILED(status))
        {
            SYSTEM_1Print("PROC_start () failed. Status = [0x%x]\n", status);
        }
    }

    /* Open the remote transport. */
    if (DSP_SUCCEEDED(status))
    {
        mqtAttrs.poolId = POOL_makePoolId(processorId, SAMPLE_POOL_ID);
        status = MSGQ_transportOpen(processorId, &mqtAttrs);
        if (DSP_FAILED(status))
        {
            SYSTEM_1Print("MSGQ_transportOpen () failed. Status = [0x%x]\n", status);
        }
     }

    /* Locate the DSP's message queue */
    /* At this point the DSP must open a message queue named "DSPMSGQ" */
    if (DSP_SUCCEEDED(status))
    {
        syncLocateAttrs.timeout = WAIT_FOREVER;
        status = DSP_ENOTFOUND;
        SYSTEM_2Sprint(dspMsgqName, "%s%d", (Uint32) SampleDspMsgqName, processorId);
        while ((status == DSP_ENOTFOUND) || (status == DSP_ENOTREADY))
        {
            status = MSGQ_locate(dspMsgqName, &SampleDspMsgq, &syncLocateAttrs);
            if ((status == DSP_ENOTFOUND) || (status == DSP_ENOTREADY))
            {
                SYSTEM_Sleep(100000);
            }
            else if (DSP_FAILED(status))
            {
                SYSTEM_1Print("MSGQ_locate () failed. Status = [0x%x]\n", status);
            }
        }
    }

    SYSTEM_0Print("Leaving MatrixARM_Create ()\n");
    return status;
}

/** ============================================================================
 *  @func   printMatrix
 *
 *  @desc   This function print out the given matrix.
 *
 *  @modif  None
 *  ============================================================================
 */
void printMatrix(Uint32 matrix[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX],Uint32 size){
    int i,j;
    
    SYSTEM_0Print("=============================================================\n");
    SYSTEM_0Print("======================== Printing Matrix ====================\n");
    for(i=0;i<size;i++){
        for(j=0;j<size;j++){
            SYSTEM_1Print("%d ",matrix[i][j]);
        }
        SYSTEM_0Print("\n");
    }
    SYSTEM_0Print("=============================================================\n");
    
}

/** ============================================================================
 *  @func   matMult
 *
 *  @desc   This function perform the multiplication of 2 matrixes.
 *
 *  @modif  None
 *  ============================================================================
 */
void matMult(Uint32 mat1[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 mat2[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 prod[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 size)
{
    int i, j, k;
    for (i = 0;i < size; i++)
    {
        for (j = 0; j < size; j++)
        {
            prod[i][j]=0;
            for(k=0;k<size;k++)
                prod[i][j] = prod[i][j]+mat1[i][k] * mat2[k][j];
        }
    }
}


/** ============================================================================
 *  @func   WaitAcknowledgement
 *
 *  @desc   This function set the necessary setting for msg.
 *          Mainly used by SendMatrix to set the number of sending elements.
 *
 *  @modif  None
 *  ============================================================================
 */
void PrepareMsg(ControlMsg *msg, Uint16 CurrEntries){
    // Edit the message and send it over
    Uint16 msgId = MSGQ_getMsgId(msg);
    
    MSGQ_setMsgId(msg, msgId);
    msg->PackageEntries = CurrEntries;
}


/** ============================================================================
 *  @func   SendMatrixMsg
 *
 *  @desc   This function will send the given message to DSP.
 *
 *  @modif  None
 *  ============================================================================
 */
void SendMatrixMsg(ControlMsg *msg){
    DSP_STATUS status = MSGQ_put(SampleDspMsgq, (MsgqMsg) msg);
    
    if (DSP_FAILED(status))
    {
        MSGQ_free((MsgqMsg) msg);
        SYSTEM_1Print("MSGQ_put () failed. Status = [0x%x]\n", status);
    }
}

/** ============================================================================
 *  @func   WaitAcknowledgement
 *
 *  @desc   This function will wait for the acknowledgement from DSP.
 *          It is used by SendMatrix to ensure the DSP received the elements of Matrix.
 *
 *  @modif  None
 *  ============================================================================
 */
void WaitAcknowledgement(ControlMsg *msg, Uint32 ExpectedRequest){
    DSP_STATUS status;
    Uint32 Information;
    
    status = MSGQ_get(SampleGppMsgq, WAIT_FOREVER, (MsgqMsg *) &msg);
    
    if (DSP_FAILED(status))
    {
        SYSTEM_1Print("MSGQ_get () failed. Status = [0x%x]. Fail to receive echo message.\n", status);
    }
    else if(DSP_SUCCEEDED(status)){
        Information = msg->PackageEntries;
        if(Information!=ExpectedRequest){
            SYSTEM_2Print("Mismatch occured! Expected Request:%d \tReceived Request:%d\n", ExpectedRequest, Information);
        }
    }
}


/** ============================================================================
 *  @func   PrepareMSGArray
 *
 *  @desc   This function retrieve the elements from Matrixes and 
 *          allocate them into the message for sending.
 *
 *  @modif  None
 *  ============================================================================
 */
Uint32 PrepareMSGArray(Uint32 CurrMatrix[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 MatrixSize, Uint16 *Row, Uint16 *Colume, Uint32 PackageEntries, ControlMsg *msg){
    Uint32 ProcessedEntries = 0;
    
    while((ProcessedEntries<PackageEntries)&&((*Row)!=MatrixSize)){
        msg->int_arg[ProcessedEntries] = CurrMatrix[(*Row)][(*Colume)];
        (*Colume)++;
        ProcessedEntries++;
        
        if((*Colume)==MatrixSize){
            (*Colume)=0;
            (*Row)++;
        }
    }
    return ProcessedEntries;
}


/** ============================================================================
 *  @func   SendMatrix
 *
 *  @desc   This function will send a Matrix to DSP with given parameter.
 *
 *  @modif  None
 *  ============================================================================
 */
void SendMatrix(ControlMsg *msg, Uint32 CurrMatrix[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 MatrixSize, Uint32 PackageEntries){
    Uint32 RemainingEnties = MatrixSize*MatrixSize;
    Uint32 CurrEntries;
    Uint32 ExpectedRequest;
    Uint16 Row=0, Colume=0;
    
    // Check the validity of the buffer size, reset PackageEntries if invalid.
    if(PackageEntries>INT_ARG_SIZE){
        SYSTEM_2Print("Warning! Message size\"%d\" is bigger than buffer size \"%d.\" \n", PackageEntries, INT_ARG_SIZE);
        SYSTEM_1Print("Message size is reset to \"%d.\" \n", INT_ARG_SIZE);
        PackageEntries=INT_ARG_SIZE;
    }
    
    while(RemainingEnties){
        CurrEntries = PrepareMSGArray(CurrMatrix, MatrixSize, &Row, &Colume, PackageEntries, msg);
        PrepareMsg(msg, CurrEntries);
        SendMatrixMsg(msg);
        
        RemainingEnties -= CurrEntries;
        ExpectedRequest = RemainingEnties;
        
        WaitAcknowledgement(msg, ExpectedRequest);
    }
}

/** ============================================================================
 *  @func   WaitMatrixMsg
 *
 *  @desc   This function will wait for a message from DSP.
 *
 *  @modif  None
 *  ============================================================================
 */
void WaitMatrixMsg(ControlMsg *msg){
    // Waiting for incoming message
    DSP_STATUS status = MSGQ_get(SampleGppMsgq, WAIT_FOREVER, (MsgqMsg *) &msg);
    if (DSP_FAILED(status))
    {
        SYSTEM_1Print("MSGQ_get () failed. Status = [0x%x]. Fail to receive echo message.\n", status);
    }
}


/** ============================================================================
 *  @func   RetrieveData
 *
 *  @desc   This function is used by ReceiveMatrix to retrieve Matrix 
 *          information stored in the message.
 *
 *  @ret    It returns the number of retrieved element of Matrix.
 *
 *  @modif  None
 *  ============================================================================
 */
Uint16 RetrieveData(ControlMsg *msg, Uint32 CurrMatrix[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 MatrixSize, Uint16 *Row, Uint16 *Colume){
    Uint16 CurrEntries = msg->PackageEntries;
    Uint16 RetrievedEntry = 0;
    
    for(RetrievedEntry=0; RetrievedEntry!=CurrEntries; RetrievedEntry++){
        //CurrMatrix[*Row][*Colume] = msg->arg1[RetrievedEntry<<2];
        CurrMatrix[(*Row)][(*Colume)] = msg->int_arg[RetrievedEntry];
        
        
        (*Colume)++;
        if((*Colume)==MatrixSize){
            (*Colume)=0;
            (*Row)++;
        }
    }
    return RetrievedEntry;
}


/** ============================================================================
 *  @func   SendAcknowledgement
 *
 *  @desc   This function will send the receive acknowledgement to DSP.
 *          It is used by ReceiveMatrix to inform the DSP with the remaining numbers
 *          of a Matrix. 
 *
 *  @modif  None
 *  ============================================================================
 */
void SendAcknowledgement(ControlMsg *msg, Uint32 ExpectedRequest){
    // Edit the message and send it over
    Uint16 msgId = MSGQ_getMsgId(msg);
    DSP_STATUS status;
    
    MSGQ_setMsgId(msg, msgId);
    //msg->PackageEntries = 1;
    //memcpy(msg->arg1, &ExpectedRequest, sizeof(ExpectedRequest));
    msg->PackageEntries=ExpectedRequest;
    
    status = MSGQ_put(SampleDspMsgq, (MsgqMsg) msg);
    if (DSP_FAILED(status))
    {
        MSGQ_free((MsgqMsg) msg);
        SYSTEM_1Print("MSGQ_put () failed. Status = [0x%x].. Fail to send acknowledgement.\n", status);
    }
}

/** ============================================================================
 *  @func   ReceiveMatrix
 *
 *  @desc   This function will receive a Matrix send by DSP.
 *
 *  @modif  None
 *  ============================================================================
 */
void ReceiveMatrix(Uint32 CurrMatrix[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 MatrixSize, ControlMsg *msg){
    Uint32 RemainingEnties = MatrixSize*MatrixSize;
    Uint32 CurrEntries=0;
    Uint16 Row=0, Colume=0;
    
    while(RemainingEnties>0){
        WaitMatrixMsg(msg);
        CurrEntries = RetrieveData(msg, CurrMatrix, MatrixSize, &Row, &Colume);
        RemainingEnties-=CurrEntries;
        SendAcknowledgement(msg, RemainingEnties);
    }
}

/** ============================================================================
 *  @func   SendCommandMessage
 *
 *  @desc   This function will send a given command to DSP.
 *
 *  @modif  None
 *  ============================================================================
 */
void SendCommandMessage(ControlMsg *msg, Uint16 Command){
    Uint16 msgId = MSGQ_getMsgId(msg);
    DSP_STATUS status;
    
    MSGQ_setMsgId(msg, msgId);
    msg->command = Command;
    
    status = MSGQ_put(SampleDspMsgq, (MsgqMsg) msg);
    if (DSP_FAILED(status))
    {
        MSGQ_free((MsgqMsg) msg);
        SYSTEM_1Print("MSGQ_put () failed. Status = [0x%x].. Fail to send acknowledgement.\n", status);
    }
}

/** ============================================================================
 *  @func   EnableDSP_Sending
 *
 *  @desc   This function send dummy Message to DSP. It should work with
 *          WaitForEnable @ DSP.
 *
 *  @usage  Use this function to ensure the communication flow.
 *          The communication flow need to follow send+Receive pattern
 *          to ensure the DSP/ARM will never overwrite the previous message,
 *          Which will cause kernal error.
 *
 *  @modif  None
 *  ============================================================================
 */
void EnableDSP_Sending(ControlMsg *msg){
    // Edit the message and send it over
    Uint16 msgId = MSGQ_getMsgId(msg);
    DSP_STATUS status;
    
    MSGQ_setMsgId(msg, msgId);
    msg->PackageEntries=0;
    
    status = MSGQ_put(SampleDspMsgq, (MsgqMsg) msg);
    if (DSP_FAILED(status))
    {
        MSGQ_free((MsgqMsg) msg);
        SYSTEM_1Print("MSGQ_put () failed. Status = [0x%x].. Fail to send acknowledgement.\n", status);
    }
}

/** ============================================================================
 *  @func   WaitForEnable
 *
 *  @desc   This function wait for dummy Message from DSP. It should work with
 *          EnableARM_Sending @ DSP.
 *
 *  @usage  Use this function to ensure the communication flow.
 *          The communication flow need to follow send+Receive pattern
 *          to ensure the DSP/ARM will never overwrite the previous message,
 *          Which will cause kernal error.
 *
 *  @modif  None
 *  ============================================================================
 */
void WaitForEnable(ControlMsg *msg){
    WaitMatrixMsg(msg);
}

/** ============================================================================
 *  @func   MatrixARM_Execute
 *
 *  @desc   This function implements the execute phase for this application.
 *
 *  @modif  None
 *  ============================================================================
 */
NORMAL_API DSP_STATUS MatrixARM_Execute(IN Uint32 MatrixSize, Uint8 processorId)
{
    DSP_STATUS  status = DSP_SOK;
    Uint32 MsgNumber=0, PackageSize=SIZE_PACKAGE_ENTRIES;
    ControlMsg *msg = &Gmsg;

    SYSTEM_0Print("Entered MatrixARM_Execute ()\n");
    
    SYSTEM_0Print("Calculating the multiplication result on the arm...\n");
    matMult(mat1,mat2,prod_arm,MatrixSize); 
    
    // Wait for DSP awake message
    status = MSGQ_get(SampleGppMsgq, WAIT_FOREVER, (MsgqMsg *) &msg);
    if (DSP_FAILED(status))
    {
        SYSTEM_1Print("MSGQ_get () failed. Status = [0x%x]. Fail to receive DSP awake message.\n", status);
    }
    SYSTEM_1Print("Message received: %s\n", (Uint32) msg->arg1);    

#if defined (EXPERIMENT)
    MsgNumber   =1;
    PackageSize =((MatrixSize*MatrixSize)/MsgNumber)+1;
    while(PackageSize!=0){
        SYSTEM_0Print("========================================================\n");
        SYSTEM_2Print("Experiment: MsgNumber:%d \tPackageSize:%d\n", MsgNumber, PackageSize);
        SYSTEM_0Print("========================================================\n");
#endif

#if defined (PROFILE)
        SYSTEM_GetStartTime();
#endif

    SendCommandMessage(msg, COMMAND_CONTINUE);
    #if !defined (SILENT)
        SYSTEM_0Print("Continue Command was sent to DSP.\n");
    #endif
    
    WaitForEnable(msg);
    #if !defined (SILENT)
        SYSTEM_0Print("Received Enable signal from DSP.\n");
    #endif

    SendMatrix(msg, mat1, MatrixSize, PackageSize);
    #if !defined (SILENT)
        SYSTEM_0Print("Matrix 1 was sent to DSP.\n");
    #endif
    
    SendMatrix(msg, mat2, MatrixSize, PackageSize);
    #if !defined (SILENT)
        SYSTEM_0Print("Matrix 2 was sent to DSP.\n");
    #endif
    
    EnableDSP_Sending(msg);
    #if !defined (SILENT)
        SYSTEM_0Print("Enable sending signal was sent to DSP.\n");
    #endif
    
    ReceiveMatrix(prod_dsp, MatrixSize, msg);
    #if !defined (SILENT)
        SYSTEM_0Print("Multiplication result matrix was received from the DSP...\n");
    #endif
    
    WaitForEnable(msg);
    #if !defined (SILENT)
        SYSTEM_0Print("Received Enable signal from DSP.\n");
    #endif

#if defined (PROFILE)
        if (DSP_SUCCEEDED(status))
        {
            SYSTEM_GetEndTime();
            SYSTEM_GetProfileInfo(MatrixSize,MsgNumber);
        }
#endif

#if defined (EXPERIMENT)
        do{
            MsgNumber+=200;
        }while(PackageSize==((MatrixSize*MatrixSize)/MsgNumber));
        PackageSize =(MatrixSize*MatrixSize)/MsgNumber;
    }
#endif
    
    #if defined (VERIFY_DATA)
        SYSTEM_0Print("Verifying the multiplication result from DSP (Based on ARM result)...\n");
        Verify(prod_arm,prod_dsp,MatrixSize);
    #endif
    
    SendCommandMessage(msg, COMMAND_TERMINATE);
    #if !defined (SILENT)
        SYSTEM_0Print("Terminate Command was sent to DSP.\n");
    #endif
    
     /* If the message received is the final one, free it. */
    MSGQ_free((MsgqMsg) msg);

    SYSTEM_0Print("Leaving MatrixARM_Execute ()\n");

    return status;
}


/** ============================================================================
 *  @func   MatrixARM_Delete
 *
 *  @desc   This function releases resources allocated earlier by call to
 *          MatrixARM_Create ().
 *          During cleanup, the allocated resources are being freed
 *          unconditionally. Actual applications may require stricter check
 *          against return values for robustness.
 *
 *  @modif  None
 *  ============================================================================
 */
NORMAL_API Void MatrixARM_Delete(Uint8 processorId)
{
    DSP_STATUS status = DSP_SOK;
    DSP_STATUS tmpStatus = DSP_SOK;

    SYSTEM_0Print("Entered MatrixARM_Delete ()\n");

    /* Release the remote message queue */
    status = MSGQ_release(SampleDspMsgq);
    if (DSP_FAILED(status))
    {
        SYSTEM_1Print("MSGQ_release () failed. Status = [0x%x]\n", status);
    }

    /* Close the remote transport */
    tmpStatus = MSGQ_transportClose(processorId);
    if (DSP_SUCCEEDED(status) && DSP_FAILED(tmpStatus))
    {
        status = tmpStatus;
        SYSTEM_1Print("MSGQ_transportClose () failed. Status = [0x%x]\n", status);
    }

    /* Stop execution on DSP. */
    tmpStatus = PROC_stop(processorId);
    if (DSP_SUCCEEDED(status) && DSP_FAILED(tmpStatus))
    {
        status = tmpStatus;
        SYSTEM_1Print("PROC_stop () failed. Status = [0x%x]\n", status);
    }

    /* Reset the error handler before deleting the MSGQ that receives */
    /* the error messages.                                            */
    tmpStatus = MSGQ_setErrorHandler(MSGQ_INVALIDMSGQ, MSGQ_INVALIDMSGQ);

    if (DSP_SUCCEEDED(status) && DSP_FAILED(tmpStatus))
    {
        status = tmpStatus;
        SYSTEM_1Print("MSGQ_setErrorHandler () failed. Status = [0x%x]\n", status);
    }

    /* Close the GPP's message queue */
    tmpStatus = MSGQ_close(SampleGppMsgq);
    if (DSP_SUCCEEDED(status) && DSP_FAILED(tmpStatus))
    {
        status = tmpStatus;
        SYSTEM_1Print("MSGQ_close () failed. Status = [0x%x]\n", status);
    }

    /* Close the pool */
    tmpStatus = POOL_close(POOL_makePoolId(processorId, SAMPLE_POOL_ID));
    if (DSP_SUCCEEDED(status) && DSP_FAILED(tmpStatus))
    {
        status = tmpStatus;
        SYSTEM_1Print("POOL_close () failed. Status = [0x%x]\n", status);
    }

    /* Detach from the processor */
    tmpStatus = PROC_detach(processorId);
    if (DSP_SUCCEEDED(status) && DSP_FAILED(tmpStatus))
    {
        status = tmpStatus;
        SYSTEM_1Print("PROC_detach () failed. Status = [0x%x]\n", status);
    }

    /* Destroy the PROC object. */
    tmpStatus = PROC_destroy();
    if (DSP_SUCCEEDED(status) && DSP_FAILED(tmpStatus))
    {
        status = tmpStatus;
        SYSTEM_1Print("PROC_destroy () failed. Status = [0x%x]\n", status);
    }

    SYSTEM_0Print("Leaving MatrixARM_Delete ()\n");
}


/** ============================================================================
 *  @func   MatrixARM_Main
 *
 *  @desc   Entry point for the application
 *
 *  @modif  None
 *  ============================================================================
 */
NORMAL_API Void Matrix_Main(IN Char8* dspExecutable, IN Uint8 processorId, IN Char8* strMatrixSize)
{
  DSP_STATUS status = DSP_SOK;
  Uint8 intMatrixSize = SYSTEM_Atoi(strMatrixSize);
 
  SYSTEM_0Print ("========== MatrixARM ==========\n");

  if ((dspExecutable != NULL) && (strMatrixSize != NULL))
  {
    if (intMatrixSize > 0xFFFF)
    {
        status = DSP_EINVALIDARG;
        SYSTEM_1Print("ERROR! Invalid arguments specified for MatrixARM application.\n MatrixSize = %d\n", intMatrixSize);
    }
    else
    {
      if (processorId >= MAX_DSPS)
      {
        SYSTEM_1Print("== Error: Invalid processor id %d specified ==\n", processorId);
        status = DSP_EFAIL;
      }

      /* create both the matrices*/
      Create_Matrix(intMatrixSize);

      /* Specify the dsp executable file name for message creation phase. */
      if (DSP_SUCCEEDED(status))
      {
          status = MatrixARM_Create(dspExecutable, strMatrixSize, processorId);

          /* Execute the message execute phase. */
          if (DSP_SUCCEEDED(status))
          {
              status = MatrixARM_Execute(intMatrixSize, processorId);
          }

          /* Perform cleanup operation. */
          MatrixARM_Delete(processorId);
      }
    }
  }
  else
  {
      status = DSP_EINVALIDARG;
      SYSTEM_0Print("ERROR! Invalid arguments specified for MatrixARM application\n");
  }
  SYSTEM_0Print ("====================================================\n");
}


#if defined (VERIFY_DATA)
/** ============================================================================
 *  @func   Verify
 *
 *  @desc   This function compare the 2 different Matrixes and 
 *          print out mismatch location.
 *
 *  @modif  None
 *  ============================================================================
 */
void Verify(Uint32 mat1[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 mat2[SIZE_MAX_MATRIX][SIZE_MAX_MATRIX], Uint32 size)
{
    Uint16 i, j;    
    
    for (i = 0;i < size; i++)
    {
        for (j = 0; j < size; j++)
        {
           if (mat1[i][j] != mat2[i][j]) 
           {
                SYSTEM_2Print("Mismatch between DSP and ARM results on row: \"%d\" and collum: \"%d\" \n", i, j);
           }
        }
    }
}
#endif /* if defined (VERIFY_DATA) */


#if defined (__cplusplus)
}
#endif /* defined (__cplusplus) */
